﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

using VNet.VisiSuite.Common.Logger;
using VNet.VisiSuite.Common.Production;
using VNet.VisiSuite.Common.Helpers;
using Infragistics.Controls.Charts;
using System.ComponentModel;
using VNet.VisiSuite.Service.Contact.Message.ProductionData;
using Infragistics;

namespace VNet.VisiSuite.Controls
{

     /// <summary>
    /// Interaction logic for ProductionControl.xaml
    /// </summary>
    public partial class DowntimeGraphControl : UserControl, INotifyPropertyChanged
    {

        #region Member variables
        
        DispatcherTimer _hide_bogus_markers;
        string _graph_title = "";

        private BrushCollection _downtime_brush;
        private GroupBy _down_time_data_group_by;
        private List<DowntimeGraphDataItemViewModel> _downtime_bar_chart_data;
        private double _maximum_bar_value;
        private double _interval;
        private string _bar_chart_header;
        private int old_number = 1;
       
        #endregion

        #region Dependencies

        public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(DowntimeGraphControl), new FrameworkPropertyMetadata(string.Empty, TitleChangedCallback));

        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }

        private static void TitleChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var ctrl = d as DowntimeGraphControl;
            ctrl._graph_title = e.NewValue as string;
            ctrl.OnPropertyChanged("GraphTitle");
        }

        public static readonly DependencyProperty GraphDataProperty = DependencyProperty.Register("GraphData", typeof(List<DowntimeGraphDataItem>), typeof(DowntimeGraphControl), new FrameworkPropertyMetadata(null, GraphDataChangedCallback));

        public List<DowntimeGraphDataItem> GraphData
        {
            get { return null; }
            set { SetValue(GraphDataProperty, value); }
        }

        private static void GraphDataChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var ctrl = d as DowntimeGraphControl;
            var data = e.NewValue as List<DowntimeGraphDataItem>;
            ctrl.SetData(data);
        }

        public static readonly DependencyProperty TitleFontColorProperty = DependencyProperty.Register("TitleFontColor", typeof(System.Windows.Media.Brush), typeof(DowntimeGraphControl), new FrameworkPropertyMetadata(new SolidColorBrush(Colors.White), TitleFontColorChangedCallback));

        public System.Windows.Media.Brush TitleFontColor
        {
            get { return (System.Windows.Media.Brush)GetValue(TitleFontColorProperty); }
            set 
            { 
                SetValue(TitleFontColorProperty, value);
                OnPropertyChanged("TitleFontColor");
            }
        }

        private static void TitleFontColorChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var ctrl = d as DowntimeGraphControl;
            var data = e.NewValue as System.Windows.Media.Brush;
            if (data != null && ctrl != null)
            {
                ctrl.TitleFontColor = data;
            }
        }

        public static readonly DependencyProperty LabelFontColorProperty = DependencyProperty.Register("LabelFontColor", typeof(System.Windows.Media.Brush), typeof(DowntimeGraphControl), new FrameworkPropertyMetadata(new SolidColorBrush(Colors.White), LabelFontColorChangedCallback));

        public System.Windows.Media.Brush LabelFontColor
        {
            get { return (System.Windows.Media.Brush)GetValue(LabelFontColorProperty); }
            set
            {
                SetValue(LabelFontColorProperty, value);
                OnPropertyChanged("LabelFontColor");
            }
        }

        private static void LabelFontColorChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var ctrl = d as DowntimeGraphControl;
            var data = e.NewValue as System.Windows.Media.Brush;
            if (data != null && ctrl != null)
            {
                ctrl.LabelFontColor = data;
            }
        }

        #endregion

        #region Properties

        public string GraphTitle
        {
            get { return _graph_title; }
        }


        public GroupBy DowntimeDataGroupBy
        {
            get { return _down_time_data_group_by; }
            set
            {
                _down_time_data_group_by = value;
                OnPropertyChanged("DowntimeDataGroupBy");
            }
        }

        public double Interval
        {
            get { return _interval; }
            set
            {
                _interval = value;
                OnPropertyChanged("MaximumBarValue");
            }
        }

        public double MaximumBarValue
        {
            get { return _maximum_bar_value; }
            set
            {
                _maximum_bar_value = value;
                OnPropertyChanged("MaximumBarValue");
            }
        }

        public BrushCollection DowntimeBrushes
        {
            get { return _downtime_brush; }
        }

        public string BarChartHeader
        {
            get { return _bar_chart_header; }
            set
            {
                _bar_chart_header = value;
                OnPropertyChanged("BarChartHeader");
            }
        }

        #endregion

        public DowntimeGraphControl()
        {

            InitializeComponent();

            _hide_bogus_markers = new DispatcherTimer(DispatcherPriority.ContextIdle, Dispatcher.CurrentDispatcher)
            {
                Interval = new TimeSpan(0, 0, 0, 0, 50)
            };
            _hide_bogus_markers.Tick += hideBogusMarkers;
            _hide_bogus_markers.Stop();

        }

        private void onSizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (e.HeightChanged)
            {
                SetBarCount((int)Math.Round(e.NewSize.Height / 40));
                _downtime_chart.UpdateLayout();
                _hide_bogus_markers.Start();
            }
        }

        public void SetData(List<DowntimeGraphDataItem> graph_data)
        {
            var data = from v in graph_data
                       group v by v.Description
                           into newGroup
                           select new DowntimeGraphDataItemViewModel
                           {
                               Color = newGroup.Max(x => x.Color),
                               Description = newGroup.Key,
                               Time = Math.Round(newGroup.Sum(x => SubtractDateTime(x.IgnoreInWaitingCalc ? x.StartTime : x.DowntimeAckTime, x.EndTime)), 2),
                           };

            var now = DateTime.Now;
            double waiting = 0.0;
            DateTime ack;
            double diff;
            foreach (var dcd in graph_data)
            {
                if (!dcd.IgnoreInWaitingCalc)
                {
                    ack = dcd.DowntimeAckTime ?? now;
                    diff = (ack - dcd.StartTime).TotalHours;
                    if (diff > 0)
                        waiting += diff;
                }
            }

            _downtime_bar_chart_data = data.ToList();
            _downtime_bar_chart_data.Add(new DowntimeGraphDataItemViewModel
            {
                Color = "#ffff0000",
                Description = "Waiting for operator",
                Time = Math.Round(waiting, 2),
            });
            _downtime_bar_chart_data = _downtime_bar_chart_data.OrderBy(d => d.Time).ToList();

            int cnt = old_number;
            old_number = -1;
            SetBarCount(cnt);

        }
        public void SetBarCount(int numberOfData)
        {
            if (numberOfData == old_number)
            {
                _hide_bogus_markers.Start();
                return;
            }

            old_number = numberOfData;

            int data_cnt = 0;
            if (_downtime_bar_chart_data != null)
                data_cnt = _downtime_bar_chart_data.Count;

            var data = new List<DowntimeGraphDataItemViewModel>();

            if (_downtime_bar_chart_data != null)
            {
                if (numberOfData <= data_cnt)
                {
                    data.AddRange(_downtime_bar_chart_data.GetRange(_downtime_bar_chart_data.Count - numberOfData, numberOfData));
                }
                else
                    data.AddRange(_downtime_bar_chart_data);
            }

            string blank = " ";
            for (int ii = data_cnt; ii < numberOfData; ii++)
            {
                data.Add(new DowntimeGraphDataItemViewModel
                {
                    Color = ii % 2 == 0 ? "#FFF57D1B" : "#FF00FF00",
                    Description = blank,
                    Time = 0,
                });
                blank += " ";
            }

            data = data.OrderBy(d => d.Time).ToList();
            Interval = Math.Round(data.Last().Time / 5, 2);
            MaximumBarValue = Interval * 6;
            // 
            var bc = new BrushCollection();
            int idx = 0;
            foreach (var item in data)
            {
                item.Idx = idx;
                bc.Add(new SolidColorBrush(ColorHelper.StringToColor(item.Color, Colors.Red)));
                ++idx;
                if (item.Time <= 0 && !string.IsNullOrWhiteSpace(item.Description))
                {
                    item.Description = blank;
                    blank += " ";
                }
            }

            _downtime_brush = bc;
            OnPropertyChanged("DowntimeBrushes");

            DowntimeDataGroupBy = new GroupBy
            {
                ItemsSource = data,
                GroupMemberPath = "Description",
                KeyMemberPath = "Description",
                ValueMemberPath = "Time"
            };

            _hide_bogus_markers.Start();

        }

        private double SubtractDateTime(DateTime? from, DateTime? to)
        {
            double diff = 0.0;

            if (from != null)
                diff = ((to == null ? DateTime.Now : to.Value) - from.Value).TotalHours;

            return diff;
        }

        private void hideBogusMarkers(object sender, EventArgs e)
        {
            _hide_bogus_markers.Stop();
            hideBogusMarkers();
        }

        private void hideBogusMarkers()
        {
            var markers = new List<Marker>();
            Marker marker = Infragistics.Windows.Utilities.GetDescendantFromType(_downtime_chart, typeof(Marker), false) as Marker;
            if (marker != null && marker.Parent.GetType() == typeof(Canvas))
            {
                Canvas canvas = marker.Parent as Canvas;
                foreach (var item in canvas.Children)
                {
                    if (item is Marker)
                    {

                        if (((Marker)item).RenderTransform.Value.OffsetX <= -75)
                        {
                            markers.Add((Marker)item);
                            ((Marker)item).Visibility = Visibility.Collapsed;
                        }
                    }
                }
                foreach (var item in markers)
                {
                    canvas.Children.Remove(item);
                }
                markers.Clear();
            }
        }

        private void downtimeSeriesLoaded(object sender, RoutedEventArgs e)
        {
            hideBogusMarkers();
        }

        #region Implement INotifiedPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion

    }

    public class DowntimeGraphDataItemViewModel : INotifyPropertyChanged
    {

        private int _idx;
        private string _color;
        private double _time;
        private string _description;

        public int Idx
        {
            get { return _idx; }
            set
            {
                _idx = value;
                OnPropertyChanged("Idx");
            }
        }

        public string Color
        {
            get { return _color; }
            set
            {
                _color = value;
                OnPropertyChanged("Color");
            }
        }

        public double Time
        {
            get { return _time; }
            set
            {
                _time = value;
                OnPropertyChanged("Time");
            }
        }

        public string Description
        {
            get { return _description; }
            set
            {
                _description = value;
                OnPropertyChanged("Description");
            }
        }

        #region Implement INotifiedPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion
    }

}
